package main

import (
	//"fmt"
	"crypto/md5"
	"encoding/hex"
	"net/http"
	"strings"

	"github.com/valyala/fasthttp"
)

type GateWay interface {
	GetKey(*fasthttp.RequestCtx) string
	GetAddresses(ctx *fasthttp.RequestCtx) ([]*http.Request, []*http.Request)
}

type DocServiceGateWay struct {
	addressBook AddressBook
	routeMap    KeyMap
}

type RepeaterGateWay struct {
	addressBook AddressBook
	routeMap    KeyMap
}

func (r *RepeaterGateWay) GetKey(*fasthttp.RequestCtx) string {
	return ""

}
func (r *RepeaterGateWay) GetAddresses(ctx *fasthttp.RequestCtx) ([]*http.Request, []*http.Request) {
	return nil, nil
}

func NewRepeaterGateWay(addrConf string) (*RepeaterGateWay, error) {
	a, err1 := NewSimpleAddressBook(addrConf)
	if err1 != nil {
		return nil, err1
	}
	k := &RepeaterKeyMap{13}

	return &RepeaterGateWay{
		addressBook: a,
		routeMap:    k,
	}, nil
}

func NewDocServiceGateWay(addrConf, redisConf string) (*DocServiceGateWay, error) {
	a, err1 := NewSimpleAddressBook(addrConf) //addressbook.go KO
	if err1 != nil {
		return nil, err1
	}

	k, err2 := NewRedisKeyMap(redisConf) //keymap.go KO
	if err2 != nil {                     //redis down掉的话

		return nil, err2
	}
	return &DocServiceGateWay{
		addressBook: a, //
		routeMap:    k, //
	}, nil
}

func (a *DocServiceGateWay) GetKey(ctx *fasthttp.RequestCtx) (ret string) {
	//LOG.Warningf("Your Request Method is %s", ctx.Request.Header.Method())
	//if ctx.Request.Header.IsGet() {
	m := ctx.QueryArgs().Peek("method")
	if string(m) == "get" { //如果
		b := ctx.QueryArgs().Peek("filename") //200/test201707141445111111111111111nbbbbbbbbbbbcc.txt
		if len(b) != 0 {
			ret = string(b)
		}
	} else {
		LOG.Warning("Your Request Method is not Get")
	}
	return
}

func parse(sv string) (status, id string) {
	s := strings.Split(sv, ":")
	if len(s) == 3 { //->更新：加多时间戳,变成3个
		status = s[0]
		id = s[1]

	}
	return
}

func (a *DocServiceGateWay) GetAddresses(ctx *fasthttp.RequestCtx) (stdRequests []*http.Request, fallbackRequests []*http.Request) {
	key := a.GetKey(ctx) //得到filename对应的值,也就是redis里的key。
	h := md5.New()
	h.Write([]byte(key))                     // 需要加密的字符串
	md5key := hex.EncodeToString(h.Sum(nil)) // 输出加密结果
	mdkey := strings.TrimLeft(md5key, "0")   //把前面的"0"去掉
	v, err := a.routeMap.Get(mdkey)          //知道redis里面对应的值，就是"状态：id"
	if err != nil {
		LOG.Warningf("query route map error: %v", err)
	}

	status, id := parse(v) //里面的value是状态跟id
	//LOG.Infof("The key and value in Redis is %s, %s : %s\n",mdkey, status, id)

	fallbackOnly := false //设置个标志位
	if status == "2" {    //skip std//因为没有redis记录value也是2
		fallbackOnly = true //状态是2或者空是存在mixfs，就不用查标准地址的了
	}

	std, fbk := a.addressBook.Get(id)
	LOG.Infof("The addresses from id %s, std is %v, fbk is %v\n", id, std, fbk)

	if !fallbackOnly {

		for _, host := range std {
			m := string(ctx.Method()) //比如get还是post等
			uri := ctx.URI()
			uri.SetHost(host) //设置host
			req, err := http.NewRequest(m, uri.String(), nil)
			req.Header.Set("Content-Type", string(ctx.Request.Header.ContentType()))
			if err != nil {
				LOG.Warningf("setup std addresses error: %v", err)
			}
			//LOG.Infof("The stdRequest is %s\n", req.RequestURI)
			stdRequests = append(stdRequests, req)

		}
	}

	for _, host := range fbk { //先都封装好，等router的handler决定采用。
		m := string(ctx.Method()) //需要一个方法
		uri := ctx.URI()
		uri.SetHost(host)
		req, err := http.NewRequest(m, uri.String(), nil) //重定向

		//query mixfs only
		req.Header.Set("Content-Type", string(ctx.Request.Header.ContentType())) //给一个key设置响应的value
		req.Header.Set("fs", "mixfs")
		if err != nil {
			LOG.Warningf("setup fallback addresses error: %v", err)
		}
		fallbackRequests = append(fallbackRequests, req) //新的请求就已经封装好了
	}

	return
}
